using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;

namespace VisualPureBasicIDE.FormDesigner.Implementations
{
    public class SelectionService : ISelectionService
    {
        private IList _selectedComponents;

        public SelectionService(IServiceProvider host)
        {
            _selectedComponents = new ArrayList();

            // we need to know when components get added and/or removed
            var changeService = (IComponentChangeService) host.GetService(typeof (IComponentChangeService));
            changeService.ComponentAdded += OnComponentAdded;
            changeService.ComponentRemoved += OnComponentRemoved;
        }

        #region ISelectionService Members

        public event EventHandler SelectionChanging;
        public event EventHandler SelectionChanged;

        public ICollection GetSelectedComponents()
        {
            return _selectedComponents;
        }

        public object PrimarySelection
        {
            get { return ((_selectedComponents != null && _selectedComponents.Count > 0) ? _selectedComponents[0] : null); }
        }

        public int SelectionCount
        {
            get { return _selectedComponents.Count; }
        }

        public bool GetComponentSelected(object component)
        {
            // is the component in our selected list
            return _selectedComponents.Contains(component);
        }

        public void SetSelectedComponents(ICollection components, SelectionTypes selectionType)
        {
            // fire changing event
            if (SelectionChanging != null)
            {
                try
                {
                    SelectionChanging(this, EventArgs.Empty);
                }
                catch
                {
                }
            }
            // dont allow an empty collection
            if (components == null || components.Count == 0)
            {
                components = new ArrayList();
            }
            bool ctrlDown = false, shiftDown = false;
            // we need to know if shift or ctrl is down on clicks 
            if ((selectionType & SelectionTypes.Primary) == SelectionTypes.Primary)
            {
                ctrlDown = ((Control.ModifierKeys & Keys.Control) == Keys.Control);
                shiftDown = ((Control.ModifierKeys & Keys.Shift) == Keys.Shift);
            }
            if (selectionType == SelectionTypes.Replace)
            {
                // discard the hold list and go with this one
                _selectedComponents = new ArrayList(components);
            }
            else
            {
                if (!shiftDown && !ctrlDown && components.Count == 1 && !_selectedComponents.Contains(components))
                {
                    _selectedComponents.Clear();
                }
                // something was either added to the selection
                // or removed
                var ie = components.GetEnumerator();
                while (ie.MoveNext())
                {
                    var comp = ie.Current as IComponent;
                    if (comp != null)
                    {
                        if (ctrlDown || shiftDown)
                        {
                            if (_selectedComponents.Contains(comp))
                            {
                                _selectedComponents.Remove(comp);
                            }
                            else
                            {
                                // put it back into the front because it was
                                // the last one selected
                                _selectedComponents.Insert(0, comp);
                            }
                        }
                        else
                        {
                            if (!_selectedComponents.Contains(comp))
                            {
                                _selectedComponents.Add(comp);
                            }
                            else
                            {
                                _selectedComponents.Remove(comp);
                                _selectedComponents.Insert(0, comp);
                            }
                        }
                    }
                }
            }
            // fire changed event
            if (SelectionChanged != null)
            {
                try
                {
                    SelectionChanged(this, EventArgs.Empty);
                }
                catch
                {
                }
            }
        }

        public void SetSelectedComponents(ICollection components)
        {
            SetSelectedComponents(components, SelectionTypes.Replace);
        }

        #endregion

        private void OnSelectionChanging(EventArgs e)
        {
            // fire changing event
            if (SelectionChanging != null)
            {
                try
                {
                    SelectionChanging(this, e);
                }
                catch
                {
                }
            }
        }

        private void OnSelectionChanged(EventArgs e)
        {
            // fire changed event
            if (SelectionChanged != null)
            {
                try
                {
                    SelectionChanged(this, e);
                }
                catch
                {
                }
            }
        }

        private void OnComponentRemoved(object sender, ComponentEventArgs e)
        {
            if (_selectedComponents.Contains(e.Component))
            {
                // fire changing event
                OnSelectionChanging(EventArgs.Empty);
                // discard component
                _selectedComponents.Remove(e.Component);
                // fire changed event
                OnSelectionChanged(EventArgs.Empty);
            }
        }

        private void OnComponentAdded(object sender, ComponentEventArgs e)
        {
            // if its not already in the list
            if (!_selectedComponents.Contains(e.Component))
            {
                // fire changing event
                OnSelectionChanging(EventArgs.Empty);
                // discard component
                _selectedComponents.Add(e.Component);
                // fire changed event
                OnSelectionChanged(EventArgs.Empty);
            }
        }
    }
}